package handler

import (
	"blog2/database"
	"blog2/jwt"
	"blog2/util"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type LoginResponse struct {
	Code  int    `json:"code"`
	Msg   string `json:"msg"`
	Uid   int    `json:"uid"`
	Token string `json:"token"`
}

const (
	SUCCESS              = 0
	ERROR_INVAILD_REQ    = 1
	ERROR_USER_NOT_EXIST = 2
	ERROR_PASSWORD_WRONG = 3
	ERROR_USERNAME_WRONG = 4
	PASSWORD_ERROR       = 5
	ERROR_USERNAME_DUP   = 6
)

func Register(c *gin.Context) {
	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, LoginResponse{ERROR_INVAILD_REQ, "invalid register request", 0, ""})
		return
	}
	util.LogRus.Infof("name %s", user.Username)
	util.LogRus.Infof("pwss %s", user.Password)

	name := user.Username
	passwd := user.Password
	if len(name) == 0 {
		c.JSON(http.StatusBadRequest, LoginResponse{ERROR_USERNAME_WRONG, "username error", 0, ""})
		return
	}

	if len(passwd) == 0 {
		c.JSON(http.StatusBadRequest, LoginResponse{ERROR_PASSWORD_WRONG, "password error", 0, ""})
		return
	}
	if database.IsUserExist(name) {
		c.JSON(http.StatusConflict, LoginResponse{ERROR_USERNAME_DUP, "user already exist", 0, ""})
		return
	}
	database.CreateUser(name, passwd)
	util.LogRus.Infof("user: %s register success", name)
	c.JSON(http.StatusOK, gin.H{"success": true, "message": "Login successful", "name": name})
}

func Login(c *gin.Context) {
	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, LoginResponse{ERROR_INVAILD_REQ, "invalid login request", 0, ""})
		return
	}
	util.LogRus.Infof("name %s", user.Username)
	util.LogRus.Infof("pwss %s", user.Password)

	name := user.Username
	passwd := user.Password
	if len(name) == 0 {
		c.JSON(http.StatusBadRequest, LoginResponse{ERROR_USERNAME_WRONG, "username error", 0, ""})
		return
	}

	if len(passwd) == 0 {
		c.JSON(http.StatusBadRequest, LoginResponse{ERROR_PASSWORD_WRONG, "password error", 0, ""})
		return
	}

	sysUser := database.GetUserByName(name)
	if sysUser == nil {
		c.JSON(http.StatusForbidden, LoginResponse{ERROR_USER_NOT_EXIST, "user not found", 0, ""})
		return
	}

	if util.MD5(passwd) != sysUser.PassWd {
		c.JSON(http.StatusForbidden, LoginResponse{PASSWORD_ERROR, "password mismatch", 0, ""})
	}
	util.LogRus.Infof("user %s(%d) login", name, sysUser.Id)
	header := jwt.DefaultHeader
	payload := jwt.JwtPayload{
		Issue:       "blog",
		IssueAt:     time.Now().Unix(),
		Expiration:  time.Now().Add(database.TOEKEN_EXPIRE).Unix(),
		UserDefined: map[string]any{jwt.UID_IN_TOKEN: sysUser.Id},
	}

	if token, err := jwt.GenJwt(header, payload, database.JWT_SECRET); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "gen jwt error"})
		return
	} else {
		refreshToken := util.RandStringRunes(20)
		database.SetToken(refreshToken, token)
		c.SetCookie("refresh_token", refreshToken,
			database.TOEKEN_EXPIRE, "/",
			"localhost",
			false,
			true)
	}

	cookie := sysUser.Id
	c.SetCookie(name, fmt.Sprintf("%d", cookie), 3600*10, "/", "", false, true)
	c.JSON(http.StatusOK, gin.H{"success": true, "status": "Login successful", "uid": sysUser.Id})
}

func GetAuthToken(c *gin.Context) {
	refreshToken := c.Param("refresh_token")
	authToken := database.GetToken(refreshToken)
	c.String(http.StatusOK, authToken)
}
